#pragma once

#include <iostream>
#include <unistd.h>
#include <pthread.h>
#include <string>
#include <vector>
#include <semaphore.h>

const int gCap = 5;
template<class T>
class RingQueue{
public:
  RingQueue():_cap(gCap),_rq(_cap),_proAdd(0), _conAdd(0)
  {
    sem_init(&_roomSem, 0, _cap);
    sem_init(&_dataSem, 0, 0);
    pthread_mutex_init(&_pMutex, nullptr);
    pthread_mutex_init(&_cMutex, nullptr);
  }
  ~RingQueue()
  {
    sem_destroy(&_roomSem);
    sem_destroy(&_dataSem);

    pthread_mutex_destroy(&_pMutex);
    pthread_mutex_destroy(&_cMutex);
  }
public:
  void push(T in)
  {
    sem_wait(&_roomSem);
    proLockQueue();

    proWork(in);
    _proAdd++;
    _proAdd %= _cap;

    sem_post(&_dataSem);
    proUnlockQueue();
  }

  T pop()
  {
   sem_wait(&_dataSem);
   conLockQueue();

   int i = conWork();
   (void)i;
   _conAdd++;
   _conAdd %= _cap;

   sem_post(&_roomSem);
   conUnlockQueue();

   return i;
  }
private:
  void proLockQueue(){ pthread_mutex_lock(&_pMutex); }

  void proUnlockQueue(){ pthread_mutex_unlock(&_pMutex);  }

  void proWork(T in){ _rq[_proAdd] = in;  }

  void conLockQueue(){ pthread_mutex_lock(&_cMutex);  }

  void conUnlockQueue(){ pthread_mutex_unlock(&_cMutex); }

  T conWork()
  {
    std::cout << "consumer doing " << _rq[_conAdd] << std::endl;
    return _rq[_conAdd];
  }
private:
  int _cap;//容量
  std::vector<T> _rq;//环形队列
  sem_t _roomSem;//空间总量
  sem_t _dataSem;//数据总量
  int _proAdd;//插入位置
  int _conAdd;//消费位置

  pthread_mutex_t _pMutex;//生产者访问锁
  pthread_mutex_t _cMutex;//消费者访问锁
};
